﻿using System;
using System.Xml;
using Notoric.Model.Internal;
using Notoric.Model.Packaging;

namespace Notoric.Model.Elements
{
    /// <summary>
    /// A common base class for section interiors.
    /// </summary>
    public abstract class SectionInteriorElement : ModelElement
    {
        #region Constructors

        /// <summary>
        /// Creates a new <see cref="SectionInteriorElement"/> instance.
        /// </summary>
        /// <param name="packagePart">
        /// <para>
        /// Type: <see cref="XmlPackagePart"/>
        /// </para>
        /// <para>
        /// The package part that owns this element.
        /// </para>
        /// </param>
        /// <param name="owner">
        /// <para>
        /// Type: <see cref="SectionElement"/>
        /// </para>
        /// <para>
        /// The page element that directly owns this section.
        /// </para>
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// The <paramref name="packagePart"/> or <paramref name="owner"/> is <see langword="null"/>.
        /// </exception>
        protected SectionInteriorElement(XmlPackagePart packagePart, SectionElement owner)
            : base(packagePart, owner)
        {
            if (owner == null)
                throw new ArgumentNullException("owner");
        }

        /// <summary>
        /// Creates a new <see cref="SectionInteriorElement"/> instance.
        /// </summary>
        /// <param name="packagePart">
        /// <para>
        /// Type: <see cref="XmlPackagePart"/>
        /// </para>
        /// <para>
        /// The package part that owns this element.
        /// </para>
        /// </param>
        /// <param name="owner">
        /// <para>
        /// Type: <see cref="ModelElement"/>
        /// </para>
        /// <para>
        /// The page element that directly owns this section.
        /// </para>
        /// </param>
        /// <param name="element">
        /// <para>
        /// Type: <see cref="XmlElement"/>
        /// </para>
        /// <para>
        /// An XML element that represents this object.
        /// </para>
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="packagePart"/>, <paramref name="owner"/> or <paramref name="element"/> is <see langword="null"/>.
        /// </exception>
        protected SectionInteriorElement(XmlPackagePart packagePart, ModelElement owner, XmlElement element)
            : base(packagePart, owner, element)
        {
            if (owner == null)
                throw new ArgumentNullException("owner");

            typeAttribute = element.Attributes[PackageVocabulary.TypeAttribute];
        }
            

        #endregion

        #region ModelElement Members

        /// <inheritdoc/>
        protected override XmlElement CreateObjectElement(XmlDocument document)
        {
            var element = CreateObjectElementCore(document);

            typeAttribute = document.CreateAttribute(PackageVocabulary.TypeAttribute);
            typeAttribute.Value = GetType().FullName;

            element.Attributes.Append(typeAttribute);

            return element;
        }
        
        #endregion

        #region Protected Methods

        /// <summary>
        /// When overriden in a derived class, this method creates the XML element that will
        /// hold the data of the section interior.
        /// </summary>
        /// <remarks>
        /// This method is called from <see cref="CreateObjectElement"/>. This class automatically
        /// adds the type attribute holding the type name of the interior class.
        /// </remarks>
        /// <param name="document">
        /// <para>
        /// Type: <see cref="XmlDocument"/>
        /// </para>
        /// <para>
        /// The XML document that is used for creating the elements and attributes.
        /// </para>
        /// </param>
        /// <returns>
        /// <para>
        /// Type: <see cref="XmlElement"/>
        /// </para>
        /// <para>
        /// The created element.
        /// </para>
        /// </returns>
        protected abstract XmlElement CreateObjectElementCore(XmlDocument document);

        /// <summary>
        /// When overriden in a derived class, this method creates the content
        /// of the section interior.
        /// </summary>
        /// <remarks>
        /// The delayed content creation can be used in situations 
        /// where the content cannot be created until the section is fully initialized.
        /// </remarks>
        /// <param name="parameter">
        /// <para>
        /// Type: <see cref="Object"/>
        /// </para>
        /// <para>
        /// An implementation-specific initialization parameter.
        /// </para>
        /// </param>
        protected abstract void CreateContentCore(object parameter);

        #endregion

        #region Internal Methods

        /// <summary>
        /// When overriden in a derived class, attempts to handle an incoming border request.
        /// </summary>
        /// <remarks>
        /// The default implementation always returns <see langword="false"/> (cannot handle any request).
        /// </remarks>
        /// <param name="request">
        /// <para>
        /// Type: <see cref="Internal.SectionBorderRequest"/>
        /// </para>
        /// <para>
        /// The request data.
        /// </para>
        /// </param>
        /// <returns>
        /// <para>
        /// Type: <see cref="Boolean"/>
        /// </para>
        /// <para>
        /// <see langword="true"/> if the section interior handled the request, <see langword="false"/> otherwise.
        /// </para>
        /// </returns>
        /// <exception cref="InvalidOperationException">
        /// The <paramref name="request"/> is <see langword="null"/>.<br/>
        /// -or-<br/>
        /// The request is not recognized.<br/>
        /// -or-<br/>
        /// The request data are not valid.
        /// </exception>
        internal virtual bool HandleBorderRequest(Internal.SectionBorderRequest request)
        {
            return false;
        }

        /// <summary>
        /// When overriden in a derived class, processes an incoming border request.
        /// </summary>
        /// <remarks>
        /// The default implementation throws <see cref="NotImplementedException"/>.
        /// </remarks>
        /// <param name="request">
        /// <para>
        /// Type: <see cref="Internal.SystemBorderRequest"/>
        /// </para>
        /// <para>
        /// The request data.
        /// </para>
        /// </param>
        internal virtual void ProcessBorderRequest(Internal.InteriorRootBorderRequest request)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Creates the content of the section interior.
        /// </summary>
        /// <remarks>
        /// The delayed content creation can be used in situations 
        /// where the content cannot be created until the section is fully initialized.
        /// Another usage is to pass an initialization parameter to the interior.
        /// </remarks>
        /// <param name="parameter">
        /// <para>
        /// Type: <see cref="Object"/>
        /// </para>
        /// <para>
        /// An implementation specific initialization parameter.
        /// </para>
        /// </param>
        public void CreateContent(object parameter)
        {
            CreateContentCore(parameter);
        }

        #endregion

        #region Private Fields

        /// <summary>
        /// Holds the XML attribute that holds the type name of the interior class.
        /// </summary>
        private XmlAttribute typeAttribute;

        #endregion
    }
}
